package com.example.reeman.ymfacedemo.readface;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.support.v4.util.SimpleArrayMap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.reeman.ymfacedemo.R;
import com.example.reeman.ymfacedemo.ReemanApp;
import com.example.reeman.ymfacedemo.readface.base.SenseConfig;
import com.example.reeman.ymfacedemo.readface.model.User;
import com.example.reeman.ymfacedemo.readface.ui.icount.CountStartActivity;
import com.example.reeman.ymfacedemo.readface.util.DrawUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import dou.helper.CameraHelper;
import dou.helper.CameraParams;
import dou.utils.DLog;
import dou.utils.DeviceUtil;
import dou.utils.DisplayUtil;
import mobile.ReadFace.YMFace;
import mobile.ReadFace.YMFaceTrack;

/**
 * Created by ZJcan on 2017/3/8.
 */

public class ReadfaceView extends RelativeLayout
        implements CameraHelper.PreviewFrameListener, View.OnClickListener {

    private final String TAG = "ReadfaceView";
    private SurfaceView camera_view, pointView;
    protected CameraHelper mCameraHelper;
    protected YMFaceTrack faceTrack;

    protected int iw = 0, ih;
    protected int sw;
    protected int sh;

    private float scale_bit;
    protected boolean stop = false;
    //camera_max_width值为-1时, 找大于640分辨率为屏幕宽高等比
    private int camera_max_width = 640;

    private Context mContext;

    private SimpleArrayMap<Integer, YMFace> trackingMap;

    static TextView face_msg;
    boolean threadBusy = false;
    boolean saveImage = false;

    private Thread thread;

    boolean pause = false;

    public ReadfaceView(Context context) {
        super(context);
        this.mContext = context;
        LayoutInflater.from(context).inflate(R.layout.face_reco, this);

        sw = DisplayUtil.getScreenWidthPixels(mContext);
        sh = DisplayUtil.getScreenHeightPixels(mContext);
        Log.v(TAG, "sw: " + sw + " ,sh: " + sh);
        setCamera_max_width(-1);
        initCamera();
    }

    public void onResume() {
        startTrack();
        if (trackingMap != null && trackingMap.size() != 0) {
            trackingMap.clear();
        }
        trackingMap = new SimpleArrayMap<>();
        DrawUtil.updateDataSource();
    }

    public void onPause() {
        if (thread != null) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread = null;
        }
        stopTrack();
        mCameraHelper.stopCamera();
    }

    public SurfaceView getCamera_view() {
        return camera_view;
    }

    public void initCamera() {
        face_msg = (TextView) findViewById(R.id.face_msg);
        camera_view = (SurfaceView) findViewById(R.id.camera_preview);
        pointView = (SurfaceView) findViewById(R.id.pointView);
        camera_view.setOnClickListener(this);
        camera_view = (SurfaceView) findViewById(R.id.camera_preview);
        pointView.setZOrderOnTop(true);
        pointView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        //预设Camera参数，方便扩充
        CameraParams params = new CameraParams();
        //优先使用的camera Id,
        params.firstCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
        params.surfaceView = camera_view;
        params.preview_width = camera_max_width;
        params.preview_width = 640;
        params.preview_height = 480;

        params.camera_ori = 0;
        params.camera_ori_front = 0;
        if (DeviceUtil.getModel().equals("Nexus 6")) {
            params.camera_ori_front = 180;
            ReemanApp.reverse_180 = true;
        }

        params.previewFrameListener = this;
        getDefaultCameraId();
        mCameraHelper = new CameraHelper(mContext, params);
    }

    public synchronized void stopTrack() {

        if (faceTrack == null) {
            DLog.d("already release track");
            return;
        }
        stop = true;
        faceTrack.onRelease();
        faceTrack = null;
        DLog.d("release track success");
    }

    public synchronized void startTrack() {
        if (faceTrack != null) {
            DLog.d("already init track");
            return;
        }

        stop = false;
        iw = 0;//重新调用initCameraMsg的开关
        faceTrack = new YMFaceTrack();

        /**此处默认初始化，initCameraMsg()处会根据设备设置自动更改设置
         *人脸识别数据库之前保存在应用目录的cache目录下，可以通过另一个初始化检测器的函数
         *public boolean initTrack(Context mContext, int orientation, int resizeScale, String db_dir)
         *通过指定保存db的目录来自定义
         **/
        //人脸抠图专用接口（一般不输出此接口），需要在initTrack之前调用 默认为1
//        faceTrack.setCropScale(2);

        //人脸抠图专用接口（一般不输出此接口），需要在initTrack之前调用 默认为10
//        faceTrack.setCropMaxCache(10);

        //人脸抠图专用（一般不输出此接口），是否需要保留原图，需要在initTrack之前调用 默认为false
//        faceTrack.setCropBg(true);

        //设置人脸检测距离，默认近距离，需要在initTrack之前调用
        faceTrack.setDistanceType(YMFaceTrack.DISTANCE_TYPE_NEAR);

        //license激活版本初始化
        int result = faceTrack.initTrack(mContext, YMFaceTrack.FACE_0, YMFaceTrack.RESIZE_WIDTH_640,
                SenseConfig.appid, SenseConfig.appsecret);

        //普通有效期版本初始化
//        int result = faceTrack.initTrack(this, YMFaceTrack.FACE_0, YMFaceTrack.RESIZE_WIDTH_640);

        //设置人脸识别置信度，设置75，不允许修改

        if (result == 0) {
            faceTrack.setRecognitionConfidence(75);
//            new ToastUtil(mContext).showSingletonToast("初始化检测器成功");
        } else {
//            new ToastUtil(mContext).showSingletonToast("初始化检测器失败");
        }

    }

    @Override
    public void onPreviewFrame(final byte[] bytes, Camera camera) {
        initCameraMsg();
        if (!stop) {
            runTrack(bytes);
        }
    }


    protected void drawAnim(List<YMFace> faces, SurfaceView draw_view, float scale_bit, int cameraId, String fps) {
        DrawUtil.drawAnim(faces, draw_view, scale_bit, cameraId, fps, false);
    }

    int frame = 0;
    String regTemp = "";
    long regTime = 0;

    protected List<YMFace> analyse(final byte[] bytes, final int iw, final int ih) {

        if (pause) return null;
        if (faceTrack == null) return null;
        frame++;
        final List<YMFace> faces = faceTrack.trackMulti(bytes, iw, ih);
        if (faces != null && faces.size() > 0) {
            if (!threadBusy && !stop && frame >= 10) {
                frame = 0;

                if (trackingMap.size() > 50) trackingMap.clear();
                //只对最大人脸框进行识别
                int maxIndex = 0;
                for (int i = 1; i < faces.size(); i++) {
                    if (faces.get(maxIndex).getRect()[2] <= faces.get(i).getRect()[2]) {
                        maxIndex = i;
                    }
                }

                final YMFace ymFace = faces.get(maxIndex);
                final int anaIndex = maxIndex;
                final int trackId = ymFace.getTrackId();
                final float[] rect = ymFace.getRect();
                final float[] headposes = ymFace.getHeadpose();

                thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            threadBusy = true;
                            final byte[] yuvData = new byte[bytes.length];
                            System.arraycopy(bytes, 0, yuvData, 0, bytes.length);

                            boolean next = true;

                            if ((Math.abs(headposes[0]) > 30
                                    || Math.abs(headposes[1]) > 30
                                    || Math.abs(headposes[2]) > 30)) {
                                //角度不佳不再识别
                                next = false;
                            }

                            if (next) {
//                                for (int i = 0; i < faces.size(); i++) {
                                final YMFace ymFace = faces.get(0); // i
                                final int trackId = ymFace.getTrackId();
                                if (!trackingMap.containsKey(trackId) ||
                                        trackingMap.get(trackId).getPersonId() <= 0) {
                                    long time = System.currentTimeMillis();
                                    int identifyPerson = faceTrack.identifyPerson(0);// i
                                    int confidence = faceTrack.getRecognitionConfidence();
                                    String name = DrawUtil.getNameFromPersonId(identifyPerson);
                                    DLog.d("identify " + identifyPerson + " name: " + name + " time :" + (System.currentTimeMillis() - time) + " con = " + confidence);
//                                        saveImageFromCamera(identifyPerson, yuvData);
                                    if (!regTemp.equals(name)) {
                                        if (System.currentTimeMillis() - regTime > 10000) {
                                            regTemp = name;
                                            regTime = System.currentTimeMillis();
                                            String res = name + "您好！欢迎你";
                                            Intent intent = new Intent("CO M.MELON.RESULT");
                                            intent.putExtra("name", res);
                                            ReemanApp.getContext().sendBroadcast(intent);
                                        }
                                    }
                                    ymFace.setIdentifiedPerson(identifyPerson, confidence);
                                    trackingMap.put(trackId, ymFace);
                                }
//                                }

                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            threadBusy = false;
                        }
                    }
                });
                thread.start();
            }

            for (int i = 0; i < faces.size(); i++) {
                final YMFace ymFace = faces.get(i);
                final int trackId = ymFace.getTrackId();
                if (trackingMap.containsKey(trackId)) {
                    YMFace face = trackingMap.get(trackId);
                    ymFace.setIdentifiedPerson(face.getPersonId(), face.getConfidence());
                }
            }
        }
        return faces;
    }

    private void initCameraMsg() {
        if (iw == 0) {

            int surface_w = camera_view.getLayoutParams().width;
            int surface_h = camera_view.getLayoutParams().height;

            iw = mCameraHelper.getPreviewSize().width;
            ih = mCameraHelper.getPreviewSize().height;
            int orientation = 0;
            ////注意横屏竖屏问题
            DLog.d(getResources().getConfiguration().orientation + " : " + Configuration.ORIENTATION_PORTRAIT);

            scale_bit = surface_h / (float) ih;
            orientation = YMFaceTrack.FACE_0;

            if (ReemanApp.reverse_180) {
                orientation += 180;
            }
            if (faceTrack == null) {
                iw = 0;
                return;
            }

            faceTrack.setOrientation(orientation);
            ViewGroup.LayoutParams params = pointView.getLayoutParams();
            params.width = surface_w;
            params.height = surface_h;
            pointView.requestLayout();

        }
    }

    public int getCameraId() {
        return mCameraHelper.getCameraId();
    }

    public void setCamera_max_width(int width) {
        this.camera_max_width = width;
    }


    private void runTrack(byte[] data) {
        try {
            final List<YMFace> faces = analyse(data, iw, ih);
//            String str = "";
//            StringBuilder fps = new StringBuilder();
//            final String fps1 = fps.toString() + str;
//            runOnUiThread(new Runnable() {
//                @Override
//                public void run() {
//                    drawAnim(faces, pointView, scale_bit, getCameraId(), fps1);
//                }
//            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View v) {
        DLog.d("ReadfaceView onClick");
        mContext.startActivity(new Intent(mContext, CountStartActivity.class));
    }

    public void saveImageFromCamera(int personId, byte[] yuvBytes) {
        if (!saveImage) return;
        File tmpFile = new File("/sdcard/img/fr/out");
        if (!tmpFile.exists()) tmpFile.mkdirs();
        tmpFile = new File("/sdcard/img/fr/out" + "/img_" + System.currentTimeMillis() + "_" + personId + ".jpg");
        saveImage(tmpFile, yuvBytes);
    }

    private void saveImage(File file, byte[] yuvBytes) {

        FileOutputStream fos = null;
        try {
            YuvImage image = new YuvImage(yuvBytes, ImageFormat.NV21, iw, ih, null);
            fos = new FileOutputStream(file);
            image.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 90, fos);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fos != null;
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private int getDefaultCameraId() {
        int defaultId = -1;
        int mNumberOfCameras = Camera.getNumberOfCameras();
        Log.v("CameraActivity", "camera num: " + mNumberOfCameras);
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int i = 0; i < mNumberOfCameras; i++) {
            Camera.getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                defaultId = i;
            }
        }
        if (-1 == defaultId) {
            if (mNumberOfCameras > 0) {
                defaultId = 0;
            } else {
            }
        }
        return defaultId;
    }
}